package PCR;

/*
 * To change this template, choose Tools | Templates and open the template in
 * the editor.
 */
import java.awt.*;
import java.awt.geom.Line2D;
import java.awt.geom.QuadCurve2D;
import java.util.Vector;
import javax.swing.*;

/**
 *
 * @author rana
 */
public class DrawCurve extends JPanel {

    //Class Needed Variables
    int iterator, y, length, ys, ye;
    int initH;
    double max, min;
    char s, r, w, g;
    String seq;
    QuadCurve2D curve;
    Line2D line;
    String description = " ";
    Vector<Integer> Apoints, Cpoints, Gpoints, Tpoints;
    Vector<Double> rand = new Vector<Double>();
    Vector<Double> xrand = new Vector<Double>();
    Vector<Double> xrand2 = new Vector<Double>();
    Vector<Double> xrand3 = new Vector<Double>();
    Vector<Double> xrand4 = new Vector<Double>();
    Vector<Double> xrand5 = new Vector<Double>();
    MainFrame frm = (MainFrame) java.awt.Window.getWindows()[0];
    JLabel label, labeldesc;
    Icon icn;
    Image img;
    ImageIcon icon;

    /*
     * Public Class Constructor that initialize the Object
     */
    public DrawCurve(String sequence, int len, String descp) {
        //executing default constructor of the parent
        super();

        //initializing and declaring class variables
        iterator = y = 0;
        length = len * 20;
        seq = sequence;
        description = descp;
        label = new JLabel();


        if (description == null) {
            labeldesc = new JLabel();
        } else {
            labeldesc = new JLabel("<html>" + description + "</html>");
            labeldesc.setSize(new Dimension(1500, 100));
        }

        //removing jpanel layout manager
        this.setLayout(null);

        //setting logo and company data labels
        label.setIcon(icon);
        label.setSize(new Dimension(130, 130));
        label.setLocation(2000, 5);
        labeldesc.setLocation(20, 0);

        //adding logo and company data labels to the jpanel
        this.add(label);
        this.add(labeldesc);

        //showing change logo and change company data toolbar buttons
        frm.getLogoBtn().setEnabled(true);
        frm.getCompanyDataBtn().setEnabled(true);

        //changing jpanel background color 
        this.setBackground(Color.WHITE);

        if (checkSequence(seq) == 0) {
            //setting jpanel size after validating sequence
            setPreferredSize(new Dimension(2100, 1500));
        } else {
            JOptionPane.showMessageDialog(null, "Invalid input", "Warning!", JOptionPane.PLAIN_MESSAGE);
        }
    }

    /*
     * This function used to validate input sequence
     */
    public int checkSequence(String sequ) {
        int f = 0;
        for (int i = 0; i < sequ.length(); i++) {
            if (sequ.charAt(i) != 'A' && sequ.charAt(i) != 'C' && sequ.charAt(i) != 'G' && sequ.charAt(i) != 'T') {
                f = 1;
                break;
            }
            rand.add(210 + Math.random() * 20);
            xrand.add(Math.random() * 250 - 25);
            xrand2.add(Math.random() * 250 + 225);
            xrand3.add(Math.random() * 250 + 475);
            xrand4.add(Math.random() * 250 + 725);
            xrand5.add(Math.random() * 250 + 975);
        }

        return f;
    }

    /*
     * This function used to return reference to logo label
     */
    public JLabel getTitleLabelImage() {
        return label;
    }

    /*
     * This function used to return reference to company description label
     */
    public JLabel getTitleLabel() {
        return labeldesc;
    }

    /*
     * This is the overrided paintComponent function to draw the sequence graph
     */
    @Override
    public void paintComponent(Graphics gr) {
        super.paintComponent(gr);
        initH = 325;
        Graphics2D ga = (Graphics2D) gr;
        redeclareCharsVectors();
        ga.setStroke(new BasicStroke(2));

        if (seq.length() < 110) {
            iterator = seq.length();
        } else {
            iterator = 110;
        }
        for (int i = 0; i < iterator; i++) {
            drawSequenceChars(i, 20, initH, initH - 200, xrand, ga, iterator);
        }

        drawCharCurve(Apoints, Color.red, initH , ga);
        drawCharCurve(Cpoints, Color.BLACK, initH + 1, ga);
        drawCharCurve(Gpoints, Color.GREEN, initH - 1, ga);
        drawCharCurve(Tpoints, Color.BLUE, initH - 2, ga);

        if (seq.length() > 110) {
            redeclareCharsVectors();
            initH += 250;

            if (seq.length() < 220) {
                iterator = seq.length();
            } else {
                iterator = 220;
            }
            for (int i = 110; i < iterator; i++) {
                drawSequenceChars(i, 5, initH, initH - 200, xrand2, ga, iterator);
            }

            drawCharCurve(Apoints, Color.red, initH, ga);
            drawCharCurve(Cpoints, Color.BLACK, initH + 1, ga);
            drawCharCurve(Gpoints, Color.GREEN, initH - 1, ga);
            drawCharCurve(Tpoints, Color.BLUE, initH - 2, ga);

        }

        if (seq.length() > 220) {
            redeclareCharsVectors();
            initH += 250;

            if (seq.length() < 330) {
                iterator = seq.length();
            } else {
                iterator = 330;
            }

            for (int i = 220; i < iterator; i++) {
                drawSequenceChars(i, 5, initH, initH - 200, xrand3, ga, iterator);
            }

            drawCharCurve(Apoints, Color.red, initH, ga);
            drawCharCurve(Cpoints, Color.BLACK, initH + 1, ga);
            drawCharCurve(Gpoints, Color.GREEN, initH - 1, ga);
            drawCharCurve(Tpoints, Color.BLUE, initH - 2, ga);

        }
        if (seq.length() > 330) {
            redeclareCharsVectors();
            initH += 250;

            if (seq.length() < 440) {
                iterator = seq.length();
            } else {
                iterator = 440;
            }

            for (int i = 330; i < iterator; i++) {
                drawSequenceChars(i, 5, initH, initH - 200, xrand4, ga, iterator);
            }

            drawCharCurve(Apoints, Color.red, initH, ga);
            drawCharCurve(Cpoints, Color.BLACK, initH + 1, ga);
            drawCharCurve(Gpoints, Color.GREEN, initH - 1, ga);
            drawCharCurve(Tpoints, Color.BLUE, initH - 2, ga);

        }

        if (seq.length() > 440) {
            redeclareCharsVectors();
            //y = 0;
            initH += 250;

            if (seq.length() < 500) {
                iterator = seq.length();
            } else {
                iterator = 500;
            }

            for (int i = 440; i < iterator; i++) {
                drawSequenceChars(i, 5, initH, initH - 200, xrand5, ga, iterator);
            }

            drawCharCurve(Apoints, Color.red, initH, ga);
            drawCharCurve(Cpoints, Color.BLACK, initH + 1, ga);
            drawCharCurve(Gpoints, Color.GREEN, initH - 1, ga);
            drawCharCurve(Tpoints, Color.BLUE, initH - 2, ga);
        }
    }

    /*
     * This function used to get each Char value Made for code readability
     * inhancement
     */
    private void getCurveNextChar(Graphics2D ga, char s) {
        if (s == 'A') {
            ga.setColor(Color.RED);
            Apoints.add(y);
        } else if (s == 'C') {
            ga.setColor(Color.BLACK);
            Cpoints.add(y);
        } else if (s == 'G') {
            ga.setColor(Color.GREEN);
            Gpoints.add(y);
        } else if (s == 'T') {
            ga.setColor(Color.BLUE);
            Tpoints.add(y);
        }
    }

    /*
     * This function used to draw curve of specified char Used for code
     * readability inhancement
     */
    private void drawCharCurve(Vector<Integer> point, Color c, int yValue, Graphics2D ga) {
        for (int z = 0; z < point.size(); z++) {
            ga.setColor(c);
            if (z == 0) {
                line = new Line2D.Double(0, yValue, point.get(z), yValue);
                ga.draw(line);
            } else {
                if (point.get(z - 1) + 20 != point.get(z)) {
                    line = new Line2D.Double(point.get(z - 1) + 20, yValue, point.get(z), yValue);
                    ga.draw(line);
                }
                if (z == point.size() - 1) {
                    line = new Line2D.Double(point.get(z) + 20, yValue, length, yValue);
                    ga.draw(line);
                }
            }
        }
    }

    /*
     * This function used to redeclare Vectors to be empty
     */
    private void redeclareCharsVectors() {
        y = 0;
        Apoints = new Vector<Integer>();
        Cpoints = new Vector<Integer>();
        Gpoints = new Vector<Integer>();
        Tpoints = new Vector<Integer>();
    }

    /*
     * This function used to determine the start char in the sequence
     */
    private void drawSequenceChars(int currentIndex, int checkIndex, int line, int charPos, Vector<Double> randV, Graphics2D ga, int iterate) {
        if (currentIndex == 0) {
            r = seq.charAt(0);
            w = seq.charAt(0);
            g = seq.charAt(1);
        } else if (currentIndex == 1) {
            w = seq.charAt(0);
            r = seq.charAt(currentIndex - 1);
            g = seq.charAt(2);
        } else if (currentIndex == iterate - 1) {
            r = seq.charAt(currentIndex - 1);
            w = seq.charAt(currentIndex - 2);
            g = seq.charAt(currentIndex);
        } else {
            r = seq.charAt(currentIndex - 1);
            w = seq.charAt(currentIndex - 2);
            g = seq.charAt(currentIndex + 1);
        }
        s = seq.charAt(currentIndex);

        getCurveNextChar(ga, s);

        if (currentIndex < checkIndex) {
            if (s == r && w != r) {
                if (currentIndex != 0) {
                    if (rand.elementAt(currentIndex) <= rand.elementAt(currentIndex - 1)) {
                        rand.set(currentIndex, rand.elementAt(currentIndex - 1) + 5);
                    }
                }
            }

            if (s == r) {
                if (currentIndex == 0) {
                    ys = line;
                } else {
                    if (rand.elementAt(currentIndex) < rand.elementAt(currentIndex - 1)) {
                        max = rand.elementAt(currentIndex - 1);
                    } else {
                        max = rand.elementAt(currentIndex);
                    }
                    ys = (int) (max * 1.35);
                }
            } else {
                ys = line;
            }

            if (s == g) {
                if (currentIndex == 19) {
                    if (rand.elementAt(19) < xrand.elementAt(0)) {
                        max = xrand.elementAt(0);
                    } else {
                        max = rand.elementAt(19);
                    }
                } else {
                    if (rand.elementAt(currentIndex) < rand.elementAt(currentIndex + 1)) {
                        max = rand.elementAt(currentIndex + 1);
                    } else {
                        max = rand.elementAt(currentIndex);
                    }
                }
                ye = (int) (max * 1.35);
            } else {
                ye = line;
            }
            ga.setFont(new Font("Serif", Font.BOLD, 15));
            curve = new QuadCurve2D.Double(y, ys, y + 10, rand.elementAt(currentIndex), y + 20, ye);
            ga.draw(curve);
            ga.drawString(seq.substring(currentIndex, currentIndex + 1), y + 6, charPos);
            y += 20;
        } else {
            if (s == r && w != r) {
                if (randV.elementAt(currentIndex) <= randV.elementAt(currentIndex - 1)) {
                    randV.set(currentIndex, randV.elementAt(currentIndex - 1) + 35);
                }
            }

            if (s == r) {
                if (currentIndex == 110 || currentIndex == 220 || currentIndex == 330 || currentIndex == 440) {
                    ys = line;
                } else {
                    ys = ye;
                }
            } else {
                ys = line;
            }
            if (s == g) {
                if (currentIndex == iterate - 1) {
                    ye = line;
                } else {
                    if (randV.elementAt(currentIndex) < randV.elementAt(currentIndex + 1)) {
                        min = randV.elementAt(currentIndex);
                    } else {
                        min = randV.elementAt(currentIndex + 1);
                    }
                    if(currentIndex < 110) {
                        ye = line - (int) ((min + line) / 15);
                    } else if (currentIndex < 220) {
                        ye = line - (int) ((min + 75) / 15);
                    } else if (currentIndex < 330) {
                        ye = line - (int) ((min - 175) / 15);
                    } else if (currentIndex < 440) {
                        ye = line - (int) ((min - 425) / 15);
                    } else {
                        ye = line - (int) ((min - 675) / 15);
                    }
                }
            } else {
                ye = line;
            }

            curve = new QuadCurve2D.Double(y, ys, y + 10, randV.elementAt(currentIndex), y + 20, ye);
            ga.setFont(new Font("Serif", Font.BOLD, 15));
            ga.draw(curve);
            ga.drawString(seq.substring(currentIndex, currentIndex + 1), y + 6, charPos);
            y += 20;
        }
    }
}